import configparser

import datetime

import json

# import sys

from ctypes import CFUNCTYPE, windll
from ctypes import c_bool, c_char_p, c_int, c_long, c_ubyte, c_uint, c_void_p

from tdr import CALLBACK_CMD, SUBSCRIBE_FAIL, SUBSCRIBE_SUCCESS
from tdr import ID_SH_MARKETDATA, ID_SZ_MARKETDATA, SIP_SVR_WAN, WAN_TC
from tdr import RECEIVE_ERROR, RECEIVE_SUCCES, RSS_MODE_NEW, UI_LOGIN_NORMAL
from tdr import errorStringList

from tshmarket import PSH_StockMarketDataL2

from twisted.internet import reactor

from twisted.internet.protocol import ClientFactory, Protocol

from twisted.python import log


class MarketDataSendProtocol(Protocol):
    def connectionMade(self):
        self.factory.addClient(self)
        log.msg("有新的客户端（%s）连接！" % self.transport.getPeer())

    def connectionLost(self, reason):
        log.msg("%s 断开连接，原因是：%s" % (self.transport.getPeer(), reason))
        self.factory.delClient(self)

    def dataReceived(self, data):
        # 收到订阅请求
        self.factory.callbackRequest(self, data)


class MarketServerFactory(ClientFactory):
    protocol = MarketDataSendProtocol

    def __init__(self, parent=None):
        log.msg("开始初始化工厂...")
        self.clients = []
        self.dict_msg = []
        self.h = c_long(0)
        self.dll = windll.LoadLibrary("sipuicom64.dll")
        # 行情快照，保存最后一次收到的行情信息
        self.snapshot = {}
        cf = configparser.ConfigParser()
        cf.read("config.ini")
        # 正式服务器用配置
        # self.ini_section = "server"
        # 测试服务器用配置
        self.ini_section = cf.get("default", "default_section")
        self.server_ip = cf.get(self.ini_section, "ip")
        self.server_port = int(cf.get(self.ini_section, "port"))
        self.username = cf.get(self.ini_section, "username")
        self.init_code = cf.get("init_market", "code")
        self.init_market = cf.get("init_market", "market")
        self.init_connection()

    def __del__(self):
        #  业务完成，退订
        ret = self.dll.TDR_UnsubscribeAll(self.h)
        if ret == 0:
            log.msg('ret=0, 退订行情成功！')
        else:
            log.msg('ret=%s，错误信息为：%s' % (ret, errorStringList[ret]))
        ret = self.dll.TDR_DisConnect(self.h)
        if ret == 0:
            log.msg('ret=0, 断开连接成功！')
        else:
            log.msg('ret=%s，错误信息为：%s' % (ret, errorStringList[ret]))
        ret = self.dll.TDR_Destroy(self.h)
        if ret == 0:
            log.msg('ret=0, 销毁句柄成功！')
        else:
            log.msg('ret=%s，错误信息为：%s' % (ret, errorStringList[ret]))

    def addClient(self, newclient):
        self.clients.append(newclient)
        # 连接时，如果有初始快照，则马上发送
        if self.init_code in self.snapshot:
            send_data = json.dumps(
                self.snapshot[self.init_code]).encode('utf-8')
            newclient.transport.write(send_data)

    def delClient(self, client):
        self.clients.remove(client)

    def callback_senddata(self, data):
        send_data = json.dumps(data).encode('utf-8')
        print("准备发送数据给已连接客户：%s" % self.clients)
        for client in self.clients:
            client.transport.write(send_data)

    def callbackRequest(self, client, data):
        receive_data = json.loads(data.decode('utf-8'))
        log.msg("收到订阅请求：%s" % receive_data)
        if "event_type" in receive_data:
            if receive_data['event_type'] == CALLBACK_CMD:
                self.subscribe_action(receive_data)

    def set_OnReceiveData(self, pUserParam, nDate, nMarketId, sCode, sName,
                          uType, nServiceId, pData, nLen):
        log.msg('set_OnReceiveData: 收到接口数据推送!')
        log.msg(("pUserParam:%s, nDate:%s, nMarketId:%s,  sCode:%s, sName:%s, "
                "uType:%s, nServiceId:%s, pData:%s, nLen:%s"
                '' % (pUserParam, nDate, nMarketId, sCode,
                      sName.decode('gb2312'), uType, nServiceId, pData, nLen)))
        data = PSH_StockMarketDataL2()
        data = PSH_StockMarketDataL2.from_address(pData)

        self.dict_msg = {}
        # 直接将二进制数据传给客户端
        # self.dict_msg["data"] = data
        self.dict_msg["event_type"] = RECEIVE_SUCCES
        self.dict_msg["sCode"] = str(sCode, encoding='utf-8')
        self.dict_msg["sName"] = sName.decode('gb2312')
        for i in range(10):
            self.dict_msg["ask_price_%s" % i] = data.uAskPrice[i]
            self.dict_msg["ask_vol_%s" % i] = data.uAskVol[i]
            self.dict_msg["bid_price_%s" % i] = data.uBidPrice[i]
            self.dict_msg["bid_vol_%s" % i] = data.uBidVol[i]
        # # self.dict_msg["nTime"] = data.nTime
        # # self.dict_msg["nStatus"] = data.nStatus
        self.dict_msg["uPreClose"] = data.uPreClose
        self.snapshot[self.dict_msg["sCode"]] = self.dict_msg
        # self.dict_msg["uOpen"] = data.uOpen
        # self.dict_msg["uHigh"] = data.uHigh
        # self.dict_msg["uLow"] = data.uLow
        # self.dict_msg["uMatch"] = data.uMatch
        # self.dict_msg["uNumTrades"] = data.uNumTrades
        # self.dict_msg["iVolume"] = data.iVolume
        # self.dict_msg["iTurnover"] = data.iTurnover
        # self.dict_msg["iTotalBidVol"] = data.iTotalBidVol
        # self.dict_msg["iTotalAskVol"] = data.iTotalAskVol
        # self.dict_msg["uWeightedAvgBidPrice"] = data.uWeightedAvgBidPrice
        # self.dict_msg["uWeightedAvgAskPrice"] = data.uWeightedAvgAskPrice
        # self.dict_msg["nIOPV"] = data.nIOPV
        # self.dict_msg["iTurnover"] = data.iTurnover
        # self.dict_msg["nYieldToMaturity"] = data.nYieldToMaturity
        # self.dict_msg["uHighLimited"] = data.uHighLimited
        # self.dict_msg["uLowLimited"] = data.uLowLimited
        # self.dict_msg["sPrefix"] = data.sPrefix
        #print('print(dict_msg) in set_OnReceiveData: %s' % self.dict_msg)
        log.msg(self.snapshot)
        # 调用回调函数
        self.callback_senddata(self.dict_msg)
        self.dict_msg = {}
        # log.msg('完成回调！self.dict_msg=%s' % self.dict_msg)

    def set_OnErrorMsg(self, pUserParam, nError, nErrSource, uData):
        print('收到接口OnErrorMsg推送！')
        log.msg('收到接口OnErrorMsg推送！')
        self.dict_msg = {}
        self.dict_msg["event_type"] = RECEIVE_ERROR
        self.dict_msg["nError"] = nError
        self.dict_msg["nErrSource"] = nErrSource
        self.dict_msg["uData"] = uData
        log.msg('有回调事件！%s' % self.dict_msg)
        # 调用回调函数
        self.callback_senddata(self.dict_msg)
        self.dict_msg = {}
        log.msg('完成回调！self.dict_msg=%s' % self.dict_msg)

    def init_connection(self):
        # TDR_Create 建立句柄
        self.ONRECEIVEDATAFUNC = CFUNCTYPE(None, c_void_p, c_int, c_int,
                                           c_char_p, c_char_p, c_uint,
                                           c_int, c_void_p, c_int)
        self.ONERRORMSGFUNC = CFUNCTYPE(None, c_void_p, c_int, c_int, c_uint)
        self.cbOnReceiveData = self.ONRECEIVEDATAFUNC(self.set_OnReceiveData)
        self.cbOnErrorMsg = self.ONERRORMSGFUNC(self.set_OnErrorMsg)
        self.h = c_long(0)
        self.dll.TDR_Create.restype = c_long
        self.dll.TDR_Create.argtypes = [c_char_p, c_void_p, c_void_p,
                                        c_void_p, c_void_p, c_bool, c_bool]
        self.h = self.dll.TDR_Create(c_char_p(0), self.cbOnReceiveData,
                                     c_void_p(0), self.cbOnErrorMsg,
                                     c_void_p(0), c_bool(True), c_bool(True))
        # TDR_ConnectByDynamic 使用句柄连接服务器
        self.dll.TDR_ConnectByDynamic.restype = c_int
        self.dll.TDR_ConnectByDynamic.argtypes = [c_long, c_char_p, c_int,
                                                  c_int, c_int, c_char_p,
                                                  c_char_p, c_int, c_int]
        sIP = c_char_p(self.server_ip.encode('utf-8'))
        nPort = c_int(self.server_port)
        nIPType = c_int(SIP_SVR_WAN)
        nWanType = c_int(WAN_TC)
        sUserName = c_char_p(self.username.encode('utf-8'))
        sPassword = c_char_p("123456".encode('utf-8'))
        nLoginMode = c_int(UI_LOGIN_NORMAL)
        nTimeOutSec = c_int(15)
        ret = self.dll.TDR_ConnectByDynamic(self.h, sIP, nPort, nIPType,
                                            nWanType, sUserName, sPassword,
                                            nLoginMode, nTimeOutSec)
        if ret == 0:
            log.msg('ret=0, 登录成功！')
            log.msg('ret=0, 登录成功！')
        else:
            log.msg('ret=%s，错误信息为：%s' % (ret, errorStringList[ret]))
            log.msg('ret=%s，错误信息为：%s' % (ret, errorStringList[ret]))

        #  订阅行情
        self.dll.TDR_SubscribeByCode.restype = c_int
        self.dll.TDR_SubscribeByCode.argtypes = [c_long, c_char_p, c_char_p,
                                                 c_ubyte, c_int]

        sMarket = c_char_p(self.init_market.encode('utf-8'))
        sCode = c_char_p(self.init_code.encode('utf-8'))
        ucMode = c_ubyte(RSS_MODE_NEW)
        nServiceId = c_int(ID_SH_MARKETDATA)
        ret = self.dll.TDR_SubscribeByCode(self.h, sMarket, sCode,
                                           ucMode, nServiceId)
        if ret == 0:
            log.msg('成功订阅行情！%s.%s' % (self.init_code, self.init_market))

    def subscribe_action(self, input_dict_msg):
        if "user_input" in input_dict_msg:
            user_input = input_dict_msg["user_input"]
            self.dll.TDR_UnsubscribeByCode.restype = c_int
            self.dll.TDR_UnsubscribeByCode.argtypes = [c_long, c_char_p,
                                                       c_char_p, c_int]

            self.dll.TDR_UnsubscribeAll.restype = c_int
            self.dll.TDR_UnsubscribeAll.argtypes = [c_long]

            isSubscribed = False
            self.dict_msg = {}
            # SZ SH都用同一代码订阅一次
            _sMarket = c_char_p("SH".encode('utf-8'))
            _sCode = c_char_p(user_input.encode('utf-8'))
            _ucMode = c_ubyte(RSS_MODE_NEW)
            _nServiceId = c_int(ID_SH_MARKETDATA)
            ret = self.dll.TDR_SubscribeByCode(self.h, _sMarket, _sCode,
                                               _ucMode, _nServiceId)
            if ret == 0:
                # 记录当前订阅成功的号
                isSubscribed = True
                self.dict_msg["sCode"] = user_input
                self.dict_msg["sMarket"] = "SH"
                log.msg('订阅行情 %s.%s 成功！' % (user_input, "SH"))
            _sMarket = c_char_p("SZ".encode('utf-8'))
            _nServiceId = c_int(ID_SZ_MARKETDATA)
            ret = self.dll.TDR_SubscribeByCode(self.h, _sMarket, _sCode,
                                               _ucMode, _nServiceId)
            if ret == 0:
                # 记录当前订阅成功的号
                isSubscribed = True
                self.dict_msg["sCode"] = user_input
                self.dict_msg["sMarket"] = "SZ"
                log.msg('订阅行情 %s.%s 成功！' % (user_input, "SZ"))
            if isSubscribed:
                log.msg('成功订阅行情！%s' % user_input)
                self.dict_msg["event_type"] = SUBSCRIBE_SUCCESS
            else:
                self.dict_msg["event_type"] = SUBSCRIBE_FAIL
                self.dict_msg["sCode"] = user_input
            # 回调订阅结果
            self.callback_senddata(self.dict_msg)
            self.dict_msg = {}
            isSubscribed = False

    def print_with_dt(self, print_str):
        now = datetime.datetime.now()
        dt = now.strftime("%Y-%m-%d %H:%M:%S")
        print('%s %s' % (dt, print_str))
        #log.msg('%s %s' % (dt, print_str))

    def print_ret(self, ret):
        if ret == 0:
            log.msg('操作成功！')
        else:
            log.msg("操作失败，失败原因: %d %s" % (ret, errorStringList[ret]))


def main():
    # log.startLogging(DailyLogFile("testlog.log", "./"), setStdout=0)
    now = datetime.datetime.now().strftime('%Y-%m-%d')
    log.startLogging(open("%s.log" % now, 'w'))
    # log.startLogging(sys.stdout)
    host = "0.0.0.0"
    port = 9999
    print('在 %s:%s 开始等待连接...' % (host, port))
    log.msg('在 %s:%s 开始等待连接...' % (host, port))
    market_server = MarketServerFactory()
    reactor.listenTCP(port, market_server)
    reactor.run()


if __name__ == '__main__':
    main()
